#include "Log.h"
#include "../TimeStamp/TimeStamp.h"

#include <strings.h>
#include <string.h>
#include <stdarg.h>  // va_list

Log *Log::getInstance()
{
    static Log instance;
    return &instance;
}

void *Log::flushLogThread(void *args)
{
    return Log::getInstance()->asyncWriteLog();
}

bool Log::init(const char *fileName, int closeLog, int logBufSize, int splitLines, int maxQueueSize)
{
    if(maxQueueSize >= 1) {
        // if maxQueueSize is set, stands for asynchrnous
        isAsync_ = true;
        logQueue_ = new BlockQueue<std::string>(maxQueueSize);
        
        // create thread to write log asynchrnously
        pthread_t tid;
        pthread_create(&tid, NULL, flushLogThread, NULL);
    }

    closeLog_ = closeLog;
    logBufSize_ = logBufSize;
    splitLines_ = splitLines;

    buf_ = new char[logBufSize_];
    bzero(buf_, logBufSize_);

    char logFullName[256] = {0};
    const char* p = strrchr(fileName, '/'); // strrchr() 函数查找字符在指定字符串中从右面开始的第一次出现的位置

    if(p == nullptr) {
        snprintf(logFullName, 255, "%s_%s", TimeStamp::now().toStringForFileName().c_str(), fileName);
    }else {
        strcpy(logName_, p + 1);
        strncpy(dirName_, fileName, p - fileName + 1);
        snprintf(logFullName, 255, "%s_%s", TimeStamp::now().toStringForFileName().c_str(), logName_);
    }

    today_ = new TimeStamp(TimeStamp::now());

    fp_ = fopen(logFullName, "a");
    if(fp_ == nullptr) {
        return false;
    }
    return true;
}

void Log::writeLog(LogLevel level, const char *format, ...)
{
    char s[16] = {0};
    switch(level) {
        case DEBUG:
            strcpy(s, "[DEBUG]: ");
            break;
        case INFO:
            strcpy(s, "[INFO]: ");
            break;
        case ERROR:
            strcpy(s, "[ERROR]: ");
            break;
        case FATAL:
            strcpy(s, "[FATAL]: ");
            break;
        default:
            strcpy(s, "[INFO]:");
            break;
    }

    mutex_.lock();
    if(today_->toStringForFileName() != TimeStamp::now().toStringForFileName() || count_ % splitLines_ == 0) {
        // @TODO: create new log
    }
    mutex_.unlock();

    va_list valst; 
    va_start(valst, format);
    std::string logContent;

    mutex_.lock();
    int n = snprintf(buf_, 48, "%s %s", TimeStamp::now().toString().c_str(), s);
    int m = vsnprintf(buf_ + n, logBufSize_ - n - 1, format, valst);
    buf_[n + m] = '\n';
    buf_[n + m + 1] = '\0';
    logContent = buf_;
    mutex_.unlock();

    if(isAsync_ && !logQueue_->isFull()) {
        logQueue_->push(logContent);
    }else {
        mutex_.lock();
        fputs(logContent.c_str(), fp_);
        mutex_.unlock();
    }

    va_end(valst);
}   

void Log::flush(void)
{
    mutex_.lock();
    // 强制刷新写入流缓冲区
    fflush(fp_);
    mutex_.unlock();
}

Log::Log()
    : count_(0)
    , isAsync_(false)
    , fp_(nullptr)
    , today_(nullptr)
    , buf_(nullptr)
    , logQueue_(nullptr) {}

Log::~Log()
{
    if(fp_) {
        fclose(fp_);
    }

    if(today_) {
        delete today_;
    }
    
    if(buf_) {
        delete[] buf_;
    }

    if(logQueue_) {
        delete logQueue_;
    }
}

void* Log::asyncWriteLog()
{
    std::string singleLog;
    while(logQueue_->pop(singleLog)) {
        mutex_.lock();
        fputs(singleLog.c_str(), fp_);
        mutex_.unlock();
    }
    return nullptr;
}
